package com.advertisementsystem.aop;


import com.advertisementsystem.Dto.LoginUser;
import com.advertisementsystem.Dto.UserDTO;
import com.advertisementsystem.Mapper.SysLoginLogMapper;
import com.advertisementsystem.Mapper.SysOperationLogMapper;
import com.advertisementsystem.entity.SysLoginLog;
import com.advertisementsystem.entity.SysOperationLog;
import com.advertisementsystem.Exception.ResponseResult;
import com.advertisementsystem.utils.AddressUtils;
import com.advertisementsystem.utils.IpUtils;
import com.advertisementsystem.utils.ServletUtils;
import com.alibaba.fastjson2.JSON;

import eu.bitwalker.useragentutils.UserAgent;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired
    private SysOperationLogMapper operationLogMapper;

    @Autowired
    private SysLoginLogMapper loginLogMapper;

    private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<>();

    // 定义登录相关的URL模式
    private static final String[] LOGIN_PATHS = {
            "/user/login",
            "/user/logout"
    };

    /**
     * 判断是否是登录操作
     */
    private boolean isLoginOperation(String requestUri) {
        if (StringUtils.isEmpty(requestUri)) {
            return false;
        }
        for (String loginPath : LOGIN_PATHS) {
            if (requestUri.contains(loginPath)) {
                return true;
            }
        }
        return false;
    }

    @Before("execution(* com.advertisementsystem.Controller.*.*(..))")
    public void doBefore(JoinPoint joinPoint) {
        TIME_THREADLOCAL.set(System.currentTimeMillis());
    }

    @AfterReturning(pointcut = "execution(* com.advertisementsystem.controller.*.*(..))", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    @AfterThrowing(value = "execution(* com.advertisementsystem.controller.*.*(..))", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    protected void handleLog(JoinPoint joinPoint, Exception e, Object jsonResult) {
        try {
            // 获取当前请求
            HttpServletRequest request = ServletUtils.getRequest();
            String requestUri = request.getRequestURI();

            // 创建操作日志记录
            SysOperationLog operLog = new SysOperationLog();
            operLog.setStatus(1);
            operLog.setOperatorTime(LocalDateTime.now());

            // 获取IP地址
            String ip = IpUtils.getIpAddr(request);
            operLog.setOperatorIp(ip);
            operLog.setOperatorUrl(requestUri);

            // 判断是否是登录操作
            boolean isLogin = isLoginOperation(requestUri);
            if (isLogin) {
                handleLoginLog(joinPoint, operLog, jsonResult);
            } else {
                // 非登录操作，获取当前登录用户
                String username = getCurrentUsername();
                operLog.setOperatorName(username);
                operLog.setTitle("业务操作");
            }

            // 处理异常信息
            if (e != null) {
                operLog.setStatus(0);
                operLog.setErrorMsg(e.getMessage());
            }

            // 设置方法信息
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            operLog.setMethod(className + "." + methodName + "()");

            // 设置请求方式
            operLog.setRequestMethod(request.getMethod());

            // 设置请求参数
            String params = getRequestParams(joinPoint);
            operLog.setOperatorParam(params);

            // 设置响应结果
            if (jsonResult != null) {
                operLog.setJsonResult(JSON.toJSONString(jsonResult));
            }

            // 设置消耗时间
            operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());

            // 保存数据库
            operationLogMapper.insert(operLog);

        } catch (Exception exp) {
            log.error("记录操作日志异常：", exp);
        } finally {
            TIME_THREADLOCAL.remove();
        }
    }

    /**
     * 处理登录日志
     */
    private void handleLoginLog(JoinPoint joinPoint, SysOperationLog operLog, Object jsonResult) {
        try {
            // 获取请求信息
            HttpServletRequest request = ServletUtils.getRequest();

            // 创建登录日志
            SysLoginLog loginLog = new SysLoginLog();

            // 获取登录用户名
            String username = "unknown";
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0 && args[0] instanceof UserDTO) {
                UserDTO userDTO = (UserDTO) args[0];
                username = userDTO.getUsername();
            }

            // 设置基本信息
            loginLog.setUserName(username);
            loginLog.setIpAddr(IpUtils.getIpAddr(request));
            loginLog.setLoginLocation(AddressUtils.getRealAddressByIP(loginLog.getIpAddr()));
            loginLog.setLoginTime(LocalDateTime.now());

            // 获取浏览器和操作系统信息
            UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
            loginLog.setBrowser(userAgent.getBrowser().getName());
            loginLog.setOs(userAgent.getOperatingSystem().getName());
            // 设置登录状态
            if (jsonResult instanceof ResponseResult) {
                ResponseResult result = (ResponseResult) jsonResult;
                if (result.getCode() == 200) {
                    loginLog.setStatus(1);  // 登录成功
                    loginLog.setMsg("登录成功");
                } else {
                    loginLog.setStatus(0);  // 登录失败
                    loginLog.setMsg("登录失败: " + result.getMessage());
                }
            } else {
                loginLog.setStatus(0);
                loginLog.setMsg("登录失败: 未知错误");
            }

            // 保存登录日志
            loginLogMapper.insert(loginLog);

            // 设置操作日志
            operLog.setTitle("用户登录");
            operLog.setBusinessType(0);
            operLog.setOperatorName(username);
            operLog.setStatus(loginLog.getStatus());
            if (loginLog.getStatus() == 0) {
                operLog.setErrorMsg(loginLog.getMsg());
            }

        } catch (Exception e) {          log.error("处理登录日志异常：", e);
        }
    }

            /**
             * 获取请求参数
             */
    private String getRequestParams(JoinPoint joinPoint) {
        String requestMethod = ServletUtils.getRequest().getMethod();
        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0) {
                // 过滤掉敏感信息
                Map<String, Object> params = new HashMap<>();
                for (Object arg : args) {
                    if (arg instanceof UserDTO) {
                        UserDTO userDTO = (UserDTO) arg;
                        params.put("username", userDTO.getUsername());
                        // 不记录密码
                    } else if (arg != null) {
                        params.put(arg.getClass().getSimpleName(), arg);
                    }
                }
                return JSON.toJSONString(params);
            }
        }
        return "";
    }

    /**
     * 获取当前登录用户名
     */
    private String getCurrentUsername() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated()) {
                Object principal = authentication.getPrincipal();
                if (principal instanceof LoginUser loginUser) {
                    return loginUser.getUsername();
                } else if (principal instanceof String) {
                    // 处理匿名用户情况，principal 可能是 "anonymousUser"
                    return (String) principal;
                }
            }
            return "system";
        } catch (Exception e) {
            log.error("获取当前登录用户异常", e);
            return "unknown";
        }
    }
}